#pragma once

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <algorithm>
#include <atomic>
#include <cassert>
#include <chrono>
#include <cmath>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <ostream>
#include <sstream>
#include <string>
#include <thread>
#include <tuple>
#include <type_traits>
#include <vector>

#define _CLM_D_GRAY "\033[1;30m"
#define _CLM_GREEN "\033[32m"
#define _CLM_B_GREEN "\033[1;32m"
#define _CLM_RED "\033[31m"
#define _CLM_B_RED "\033[1;31m"
#define _CLM_BROWN "\033[33m"
#define _CLM_B_BROWN "\033[1;33m"
#define _CLM_BLUE "\033[34m"
#define _CLM_B_BLUE "\033[1;34m"
#define _CLM_MAGENTA "\033[35m"
#define _CLM_B_MAGENTA "\033[1;35m"
#define _CLM_CYAN "\033[36m"
#define _CLM_B_GREY "\033[1;37m"
#define _CLM_END "\033[0m"
#define _CLM_WHITE_FG_RED_BG "\033[37;41m"

std::string usToString(uint64_t us);

class Timer {
 public:
  Timer() : duration_ms(0) { reset(); }
  Timer(size_t _duration_ms) : duration_ms(_duration_ms) { reset(); }
  inline bool timeout() { return timeover(); }
  bool timeover() {
    auto cur = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = cur - start;
    if (duration_ms < elapsed.count() * 1000) return true;
    return false;
  }
  uint64_t getTimeSec() {
    auto cur = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = cur - start;
    return (uint64_t)(elapsed.count());
  }
  uint64_t getTimeMs() {
    auto cur = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = cur - start;
    return (uint64_t)(elapsed.count() * 1000);
  }
  uint64_t getTimeUs() {
    auto cur = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed = cur - start;
    return (uint64_t)(elapsed.count() * 1000000);
  }
  void reset() { start = std::chrono::system_clock::now(); }
  void resetSec(size_t _duration_sec) {
    duration_ms = _duration_sec * 1000;
    reset();
  }
  void resetMs(size_t _duration_ms) {
    duration_ms = _duration_ms;
    reset();
  }

 private:
  std::chrono::time_point<std::chrono::system_clock> start;
  size_t duration_ms;
};
